package com.ismarkendenis.vernamcipher;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;

public class VernamCipher 
{
	
	public static void main(String[] args)
	{
		String plain1     = "confidentiality";
		String key1       = "abcdefghijklmno";
		
		Integer[] cipher2 = {2, 13, 13, 2, 12, 2, 2, 6, 29, 3, 10, 0, 4, 26, 22};
		String key2       = "securityaspects";
		
		String plain3     = "securityaspects";
		Integer[] key3    = {113, 104, 110, 119, 126, 107, 118, 127, 124, 112, 122, 101, 103, 110, 101};
		
		VernamCipher vernamCipher = new VernamCipher();
		
		System.out.println("With plaintext 'confidentiality' and key 'abcdefghijklmno', you get cipher: " + vernamCipher.encrypt(plain1, key1));
		System.out.println("To get plaintext 'securityaspects' from the previous cipher, you need key: " + vernamCipher.decrypt(cipher2, key2));
		System.out.println("With plaintext 'securityaspects' and key '113, 104, 110, 119, 126, 107, 118, 127, 124, 112, 122, 101, 103, 110, 101', you get cipher: " + vernamCipher.encrypt(plain3, key3));
	}
	
	public ArrayList<Integer> decrypt(Integer[] cipher, String key)
	{
		ArrayList<String> keybits    = stringToBits(key);
		ArrayList<String> cipherbits = decimalToBits(cipher);
		ArrayList<String> plainbits  = getcipherBits(keybits, cipherbits);
		
		return bitsToDecimal(plainbits);
	}
	
	public ArrayList<Integer> encrypt(String plain, String key)
	{
		ArrayList<String> plainbits  = stringToBits(plain);
		ArrayList<String> keybits    = stringToBits(key);
		ArrayList<String> cipherbits = getcipherBits(plainbits, keybits); 
		
		return bitsToDecimal(cipherbits);
	}
	
	public ArrayList<Integer> encrypt(String plain, Integer[] key)
	{
		ArrayList<String> plainbits  = stringToBits(plain);
		ArrayList<String> keybits    = decimalToBits(key);
		ArrayList<String> cipherbits = getcipherBits(plainbits, keybits);
		
		return bitsToDecimal(cipherbits);
	}
	
 	public static ArrayList<String> getcipherBits(ArrayList<String>plainbits, ArrayList<String> keybits)
	{
		ArrayList<String> cipherbits = new ArrayList<String>();
		
		for (int i = 0; i < plainbits.size();i++)
		{
			String cipherByte = "";
			for (int j = 0; j < plainbits.get(i).length(); j++)
			{
				if (plainbits.get(i).charAt(j) == keybits.get(i).charAt(j))
				{
					cipherByte += 0;
				}
				else
				{
					cipherByte += 1;
				}
			}
			cipherbits.add(cipherByte);
		}
		
		return cipherbits;
	}
	
	public static ArrayList<String> stringToBits(String s)
	{
		byte[] bytes = {};
		ArrayList<String> stringArray = new ArrayList<String>();
		
		try 
		{
			bytes = s.getBytes("US-ASCII");
		} 
		catch (UnsupportedEncodingException e) 
		{
			e.printStackTrace();
		}
		
		for (int i = 0; i < bytes.length; i++)
		{
			stringArray.add(Integer.toBinaryString(bytes[i]));
		}
		
		return stringArray;
	}
	
	public static ArrayList<String> decimalToBits(Integer[] cipher)
	{
		ArrayList<String> bits = new ArrayList<String>();
		
		for (int c : cipher)
		{
			String bitcode = Integer.toBinaryString(c);
			
			while(bitcode.length() < 7)
			{
				bitcode = "0" + bitcode;
			}
			bits.add(bitcode);
		}
		
		return bits;
	}
	
	public static ArrayList<Integer> bitsToDecimal(ArrayList<String> bitCode)
	{
		ArrayList<Integer> decimalCode = new ArrayList<Integer>();
		
		for (String b : bitCode)
		{
			decimalCode.add(Integer.parseInt(b, 2));
		}
		
		return decimalCode;
	}
	
	public static String bitsToString(ArrayList<String> bitCode)
	{
		String word = "";
		
		for (String b : bitCode)
		{
			word += (char) Integer.parseInt(b, 2);
		}
		
		return word;
	}	
}